﻿@page "/extension/{Module}/{Target}/{Id?}"

@using Gurux.DLMS.AMI.Shared.DIs

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.AMI.Shared.Rest
@using Gurux.DLMS.AMI.Shared.Enums
@using System.IO
@using Gurux.DLMS.AMI.Module
@using System.Linq
@using System.Net.Http.Headers
@using System.Text.Json
@using Microsoft.Extensions.Logging
@using Microsoft.Extensions.Options

@inject GXModuleService modules
@inject NavigationManager NavigationManager
@inject HttpClient Http
@inject IGXNotifier Notifier
@inject ILogger<ExtensionView> Logger
@inject GXModuleService modules

@if (_extensionUI != null)
{
    var onSave = EventCallback.Factory.Create
     <object>
         (this, async arg =>
         {
             try
             {
                 Notifier.ProgressStart();
                 _moduleSettings = arg;
                 //Save module settings.
                 _settings.Value = JsonSerializer.Serialize(_moduleSettings);
                 if (_settings.Id == Guid.Empty)
                 {
                     _settings.Name = Target;
                     await Http.PostAsJson("api/UserSetting/Add", new GXUserSetting[] { _settings });
                 }
                 else
                 {
                     await Http.PostAsJson("api/UserSetting/Update", new GXUserSetting[] { _settings });
                 }
                 //Update concurrency stamp.
                 GetUserSettings? tmp = await Http.GetAsJsonAsync
        <GetUserSettings>
            ("api/UserSetting?Name=" + Target);
                 if (tmp?.Item != null)
                 {
                     _settings.ConcurrencyStamp = tmp.Item.ConcurrencyStamp;
                 }
             }
             catch (Exception ex)
             {
                 Logger.LogError(ex.Message);
                 Notifier.ProcessError(ex);
             }
             finally
             {
                 Notifier.ProgressEnd();
             }
         });
    RenderFragment renderFragment = (builder) =>
    {
        builder.OpenComponent(0, _extensionUI);
        if (_canSave)
        {
            builder.AddAttribute(8, "SettingsChanged", onSave);
        }
        builder.AddComponentReferenceCapture(0, inst => { _extension = inst; });
        builder.CloseComponent();
    };
    <AuthorizeView Roles="@_roles" Policy="@_policy">
        <Authorized Context="AuthorizedContext">
            <EditForm Model="@this">
                @renderFragment
            </EditForm>
        </Authorized>
        <NotAuthorized>
            <p>@Properties.Resources.NotAuthorized</p>
        </NotAuthorized>
    </AuthorizeView>
}

@code {
    [CascadingParameter]
    private Task<AuthenticationState>? _authenticationState { get; set; }

    /// <summary>
    /// Target module.
    /// </summary>
    [Parameter]
    public string? Module { get; set; }

    /// <summary>
    /// Module action.
    /// </summary>
    [Parameter]
    public string? Target { get; set; }

    /// <summary>
    /// Module target ID.
    /// </summary>
    [Parameter]
    public string? Id { get; set; }

    private Type? _extensionUI;
    private object? _extension = null;
    object? _moduleSettings;
    private GXUserSetting _settings = new GXUserSetting();

    bool _canSave;
    /// <summary>
    /// Policy that can access this extension view.
    /// </summary>
    string? _policy = null;
    /// <summary>
    /// Roles that can access this extension view.
    /// </summary>
    string? _roles = "Admin";

    protected override async Task OnInitializedAsync()
    {
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            Notifier.Clear();
            if (string.IsNullOrEmpty(this.Module) || string.IsNullOrEmpty(Target))
            {
                NavigationManager.NavigateTo("404");
            }
            foreach (var asm in modules.Assemblies)
            {
                foreach (var type in asm.GetExportedTypes())
                {
                    if (type.IsAbstract || !type.IsClass || type.FullName == null)
                    {
                        continue;
                    }
                    if (type.GetInterfaces().Contains(typeof(IAmiModule)))
                    {
                        IAmiModule? tmp = (IAmiModule?)asm.CreateInstance(type.FullName);
                        if (string.Compare(Target, tmp?.Id, true) == 0)
                        {
                            _extensionUI = tmp.Extension;
                            break;
                        }
                    }
                }
                if (_extensionUI != null)
                {
                    break;
                }
            }
            if (_extensionUI == null)
            {
                //Find from development extensions.
                foreach (var type in modules.Types)
                {
                    if (type.IsAbstract || !type.IsClass || type.FullName == null)
                    {
                        continue;
                    }
                    if (type.GetInterfaces().Contains(typeof(IAmiModule)))
                    {
                        IAmiModule? tmp = (IAmiModule?)Activator.CreateInstance(type);
                        if (string.Compare(Target, tmp?.Id, true) == 0)
                        {
                            _extensionUI = tmp.Extension;
                            break;
                        }
                    }
                }
            }
            if (_extensionUI != null)
            {
                //Check access rights.
                foreach (AuthorizeAttribute? it in _extensionUI.GetCustomAttributes(typeof(AuthorizeAttribute), true))
                {
                    if (!string.IsNullOrEmpty(it?.Policy))
                    {
                        _policy = it.Policy;
                    }
                    if (!string.IsNullOrEmpty(it?.Roles))
                    {
                        //Admin can see all the extensions.
                        _roles = "Admin," + it.Roles;
                    }
                }
                //Check can module save user settings.
                foreach (var it in _extensionUI.GetProperties())
                {
                    if (it.Name == "SettingsChanged")
                    {
                        _canSave = true;
                        break;
                    }
                }
                if (_canSave)
                {
                    //Get user-depending extension settings.
                    GetUserSettings? tmp = await Http.GetAsJsonAsync<GetUserSettings>("api/UserSetting?Name=" + Target);
                    if (tmp?.Item != null)
                    {
                        _settings = tmp.Item;
                        var settings = _extensionUI.GetProperty("Settings");
                        if (settings != null && !string.IsNullOrEmpty(_settings.Value))
                        {
                            _moduleSettings = JsonSerializer.Deserialize(_settings.Value, settings.PropertyType);
                        }
                        else
                        {
                            //Extension doesn't want to save settings.
                            _moduleSettings = null;
                        }
                    }
                }
                if (_extension != null)
                {
                    if (_moduleSettings != null)
                    {
                        //Update user settings for the module.
                        foreach (var it in _extensionUI.GetProperties())
                        {
                            if (it.Name == "Settings")
                            {
                                it.SetValue(_extension, _moduleSettings);
                                break;
                            }
                        }
                    }
                    if (_extension is IAmiUIExtension ui)
                    {
                        await ui.InitializedAsync();
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }
}
